Computer security has become an intensely studied and vital field of research in academic, governmental, and commercial computing organizations. While manufacturers and users of computer systems have, for many years, attempted to provide secure computer systems to control access to stored data, processing resources, and other computational resources within a computer system, the considerable efforts of computer manufacturers and users have not yet successfully produced secure computer systems. Many notorious computer-system-security breaches have been widely publicized in the past few years, including theft of money from ATM systems and computer systems within financial institutions, acquisition of highly confidential and secret documents and information from governmental, commercial, and private computer systems, a number of extremely costly and damaging computer viruses spread through email and other internet-related services, and many other severe security breaches.
Computer security issues in commercial computer systems have been, to date, addressed in a largely reactive fashion. In general, security issues are recognized after production of new commercial computer systems containing potential security breaches, and are addressed through somewhat ad hoc, post-design methodologies. Security techniques generally evolve as a result of the evolution of underlying computing technologies and resources. Although various security issues can be recognized and patched in existing systems, many additional potential security issues often remain unrecognized and available for later discovery through inadvertent and unintended errors or, more commonly, through systematic probing of computer system security features by malicious users and computing entities.
The invention, to be discussed below, relates to operating systems and operating system and computer system security. To facilitate this discussion, and to facilitate further background discussion, a concise overview of computer hardware architecture and operating systems is first provided, below.
FIG. 1 is a block diagram showing hardware, operating-system, and application-program layers within a generalized computer system. A computer system 100 can be considered to comprise a hardware layer 102, an operating system layer 104, and an application-programming layer 106. Computer systems are quite complex, with many additional components, sub-layers, and logical entity interrelationships, but the 3-layer hierarchy shown in FIG. 1 represents a logical view of computer systems commonly employed within the computer software and hardware industries.
The hardware layer 102 comprises the physical components of a computer system. These physical components include, for many computer systems, a processor 108, memory storage components 110, 112, and 114, internal buses and signal lines 116–119, bus interconnect devices 120 and 122, and various microprocessor-based peripheral interface cards 124–129. The processor 108 is an instruction-execution device that executes a stream of instructions obtained by the processor from internal memory components 110, 112, and 114. The processor contains a small number of memory storage components referred to as registers 130 that can be quickly accessed, and modem processors may, as well, include a relatively small amount of stored instructions. In general, data and instructions are read from read-only memory (“ROM”) component 110, and read from, and written to, the memory components 112 and 114, via internal buses 116 and 117 and the bus interconnect device 120. Far greater data storage capacity resides in peripheral data storage devices such as disk drives, CD-ROM drives, DVD drives, and other such components that are accessed by the processor via internal buses 116, 118, and 119, interconnect devices 120 and 122, and one or more of the peripheral device interconnect cards 124–129. For example, the stored instructions of a large program may reside on a disk drive for retrieval and storage in internal memory components 112 and 114 on an as-needed basis during execution of the program. More sophisticated computers may include multiple processors with correspondingly more complex internal bus interconnections and additional components.
The operating system layer 104 is a logical layer comprising various software routines that execute on the processor 108 or one or more of a set of processors and that manage the physical components of the computer system. A computer operating system is generally thought of as the lowest-level software layer in a computer system, and serves to create a combined hardware/software environment in which user programs, including application programs, can run and which supports interactive use of computer-system services by users through various input/output (“I/O”) devices.
Operating system routines, in a traditional computer system, run at higher priority than user-level application programs, coordinating concurrent execution of many application programs and providing each application program with a run-time environment that includes processor time, at least one area of memory addressed by an address space provided to the application program, and a variety of data input and output services, including access to memory components, peripheral devices, communications media, and other internal and external devices.
Each currently running program is executed in the context of a process, a logical entity defined by various state variables and data structures managed by the operating system. One important internal data structure managed by the operating system is one or more process queues 132 that contain, for each currently active process, a process-control block or similar data structure that stores data that defines the state of the currently active process managed by the operating system. The operating system 104 provides, to each concurrent program, the illusion that the program is employing the computer hardware 102 in a continuous fashion, although, in reality, the operating system 104 runs only at most one program per processor at any given instant, rapidly switching execution between the various currently active programs, restoring the context of a program prior to restarting execution of the program, and storing the context of a program in memory as the program is idled to allow another program to run. The operating system 104 also provides, to executing programs, somewhat generalized, logical interfaces through which the executing programs can access and employ many types of remote and local computing resources, including physical memory, mass-storage devices, communications networks, I/O devices, and other resources.
The application-programming and user interface layer 106 is the user-visible layer of the computer system. An application program comprises a set of stored instructions and data 134 within a memory area addressed within an address space provided by the operating system to the process executing the application program, and resources 136–142 accessed by the application program through the operating-system interface that allow the application program to store data to, and retrieve data from, external devices and database management systems, obtain system information, such as the values of an internal clock and system configuration information, and to access additional services. The memory area and resources are implemented in hardware memory, data storage, communications, and other components, and are shown in FIG. 1 within the application-programming and user interface layer 106 in a logical sense.
In early computer systems, there were no operating systems. FIG. 2 is a block diagram illustrating an early computer system. A single application program 202 runs directly on the computer system hardware 204, interfacing to the hardware via a simple hardware interface 206 comprising the machine instructions and registers provided by the hardware. An application program is loaded into the machine as a paper tape or deck of punched cards along with a set of paper tapes or punched cards encoding various computational libraries and I/O libraries providing routines needed by the application program at runtime. In early machines, an application program is loaded and executed to completion. Scheduling of application program execution is carried out by human system managers, with the paper tapes or punched cards encoding application programs physically queued in shelves or trays and manually re-ordered from first-in-first-executed order according to the priorities assigned to application programs.
Operating systems arose from a desire to automate the system management related to loading and executing application programs, and from a need to provided concurrent use and interactive use of computer systems to a number of users. Operating systems were developed for mainframe computer systems, such as the IBM System/360 series. FIG. 3 is a block diagram illustrating the logical position of an operating system within an early mainframe computer. The most privileged part of an operating system, usually called the Kernel, 302 interfaces to the computer hardware 304 through a hardware interface including non-privileged and privileged instructions and registers and hardware interruption mechanisms. The registers and instructions are partitioned into privileged and non-privileged sets in order to reserve certain machine functionality for the operating system and to prevent higher-level application programs from accessing that functionality. For example, registers involved in setting the execution priority of a running program are generally privileged, to prevent an application program from frustrating or corrupting the operating system's scheduling and prioritization of application programs. The operating system has full access to both privileged and non-privileged instructions and registers and to hardware interruption mechanisms, but exposes only non-privileged instructions and registers to application programs via the operating-system interface 308. In addition to the non-privileged instructions, the operating-system interface provides many different operating-system service routines. For example, when running on top of an operating-system interface, an application program 310 does not need to be packaged together with I/O libraries, as in the case of early computer systems lacking operating systems, but can access I/O devices via I/O service routines provided by the operating system 302.
In modern personal computer (“PC”) systems, the operating system inhabits a roughly equivalent logical position within the system. FIG. 4 is a block diagram of the application, operating system, and hardware layers of a modern PC. The interface 402 between the PC hardware 404 and the operating system 406, however, includes a new firmware-services interface that may be optionally exposed, in part, to an application program. The firmware interface includes various firmware routines that provide control over hardware features, including display features.
Hardware privilege levels are used within modern operating systems to partition resources between the operating system and other routines and programs. FIGS. 5A–D illustrate the fundamental privilege-level mechanisms and features in a generalized computer hardware system. At any given period in time, an executing program is associated with a current privilege level. The privilege level is maintained in a bit-field 502 within a processor status register 504. The processor status register controls and reflects the fundamental state of the processor. Many current computer systems employ only two privilege levels, privileged and non-privileged, and therefore need only a single bit in the privilege-level bit field to control the current privilege level. Modem computer systems, as well as a few earlier systems, employ more than two privilege levels. In general, n bits in the privilege-level bit field allow for 2n discrete privilege levels, ranging from privilege level 0, usually the most privileged of the privilege levels, to privilege level 2n−1. Resources within the computer system are generally partitioned into sets of resources accessible only to processes executing at one or more privilege levels. For example, as shown in FIG. 5B, many common machine architectures partition the instruction set 506 into a set of non-privileged instructions 508 and privileged instructions 510. The non-privileged instructions are accessible to processes running at any privilege level, while the privileged instructions are accessible only to processes running at privilege level 0. In general, operating system kernel routines run at privilege level 0, and, if correctly constructed, can exclusively use the privileged instruction set to manage execution of application-level process creation, execution, and scheduling. In addition, as shown in FIG. 5C, the entire hardware register set 512 is partitioned into a non-privileged register set 514 and a privileged register set 516, with non-privileged registers accessible to processes running at any privilege level, while the privileged registers are accessible only to processes running at privilege level 0. The processor status register 504, for example, is a privileged register, to prevent non-kernel code from attempting to promote the current privilege level and access resources, which are intended to be inaccessible to non-kernel code.
Memory can also be partitioned with respect to privilege levels, as shown in FIG. 5D. In general, memory 518 is partitioned into pages (e.g. memory page 520). A memory page is a basic unit of memory with respect to I/O operations, virtual-memory-to-physical-memory mapping, and other types of operating system activities. In many systems, each memory page may be associated with an indication of one or more privilege levels, such as privilege-level indication 522 associated with page 520. These indications may be directly incorporated as tags within the memory pages, or may reside in auxiliary data structures that describe or reference the memory pages. While instructions sets and registers are often partitioned into only two different privilege-level-based partitions, as discussed above, partitioning of memory pages with respect to privilege level may be more complex. For example, one page may be made accessible to processes executing at privilege levels 0–2, another may be made accessible to processes executing at all 2n privilege levels, and other may be accessible only to processes executing at privilege level 0.
Partitioning of resources is a fundamental technique used in the design of reliable and secure operating systems, but is not, by itself, sufficient. There are many aspects of security and reliability that cannot be addressed solely through hardware-level privilege-based partitioning. FIG. 6 illustrates one example of a security and reliability breach present in many modern computer systems. A simplified block-diagram representation 602 of a computer system is shown in FIG. 6. Normally, an operating system vendor supplies the operating system layer 604 to run on the hardware layer 606 provided by a hardware vendor. In many modern computer systems, 3rd party vendors may provide peripheral hardware I/O devices that are incorporated into the computer-system hardware by the hardware vendor or by computer system owners. These peripheral hardware devices need interfacing software routines, known as I/O drivers that are installed to run within, or in conjunction with, the operating system. For example, in FIG. 6, I/O driver 608 resides within the operating system layer 604. In general, the I/O driver 608 needs to run at the highest privilege level in order to interface with privileged register and memory resources that are not intended to be accessible to application-level programs. For example, in FIG. 6, a portion 610 of the memory resources for the machine is shown. One area in memory 612 is intended for access by application-level programs. Another area of memory 614 is intended for access only by operating system routines. This area may include, for example, stored cryptographic key information 616. Another area in memory 618 is intended for use by the I/O driver 608 and the operating system, containing I/O buffers that the I/O driver and operating system employ to exchange data.
If the I/O driver is correctly written, and does not contain malicious code, the I/O driver routines only read from, and write to, the I/O buffer area 618 of memory, and cannot interfere, through memory operations, with either the operating system or with application routines. However, neither the hardware vendor nor the operating-system vendor have control over the contents of the I/O driver. They may employ an authentication method to determine that the I/O driver was received from a particular 3rd party vendor. They may even test the I/O driver prior to installing it. Some 3rd party vendors do not make source code for their I/O drivers available for inspection, limiting the extent to which the I/O driver can be independently verified by the operating system and hardware vendors. It is possible that the I/O driver may include either Trojan-horse code inserted for malicious purposes, or may contain bugs. In either case, the I/O driver may attempt to access portions of memory outside the I/O buffer area 618 to which the I/O driver was intended to be restricted. In many current computer systems, there is nothing to prevent the I/O driver from reading and writing any memory area within the system, because the I/O driver generally executes at kernel-level privilege. Once an incorrect or malicious program begins to run at kernel-level privilege, the program can employ the full set of resources available to the operating system. In the current case, for example, a Trojan-horse routine within the I/O driver may begin execution during I/O-driver operation, access the cryptographic keys 616 stored in memory allocated for the operating system 614, and use other operating system routines and hardware resources to export the cryptographic keys to a remote entity.
The problem illustrated in FIG. 6 is only one of an almost limitless number of security problems that may arise in current computer systems. For many identified problems, various measures can be designed and retrofitted into the operating system in an attempt to close or narrow the system vulnerabilities associated with the problem. However, such measures are generally specific to only one or a small number of problems, and a great number of additional vulnerabilities remain undetected and potential sources of future security problems. Sometimes, the attempted fixes are incomplete or incorrect. In certain cases, the attempted fixes are themselves the source of additional problems. To date, fully secure, general purpose, commercial computer systems have not been produced, despite recognition of the desirability to produce secure systems. In fact, although the general notion of computer system security has motivated design and development efforts for many years, a clear and comprehensive understanding of computer security and of rational approaches to solving computer-security-related issues has remained elusive. Designers, manufacturers, developers, and users of computer systems have thus recognized a need for a comprehensive understanding of computer security, secure computer systems, and computer-security methodologies.